package com.gonsin.easycount.plugin.impl;

import com.gonsin.easycount.config.JsonSerializer;
import com.gonsin.easycount.config.RedisConfig;
import com.gonsin.easycount.plugin.OuterCache;
import com.mchange.v2.lang.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.lang.reflect.Type;
import java.util.*;

import static com.google.common.collect.Iterables.isEmpty;

public class LocalRedisCache implements OuterCache {

    private JedisPool jedisPool;

    public LocalRedisCache(RedisConfig redisConfig) {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(redisConfig.getMaxTotal());
        config.setMaxIdle(redisConfig.getMaxIdle());
        config.setMaxWaitMillis(redisConfig.getMaxWaitMillis());
        config.setTestOnBorrow(redisConfig.isTestOnBorrow());
        if (redisConfig.getPassword() != null && !redisConfig.getPassword().equals("")) {
            this.jedisPool = new JedisPool(config, redisConfig.getHost(), redisConfig.getPort(), redisConfig.getTimeout(), redisConfig.getPassword());
            return;
        }
        this.jedisPool = new JedisPool(config, redisConfig.getHost(), redisConfig.getPort(), redisConfig.getTimeout());
    }

    @Override
    public void cleanSet(Collection<String> setNames) {
        if(setNames == null || isEmpty(setNames)){
            return;
        }
        List<String> items = new ArrayList<>(setNames);
//        Object item = items.get(0);
//        List<byte[]> strings = items.stream().map(i -> {
//            JsonSerializer serializer = new JsonSerializer(item.getClass());
//            return serializer.serialize(i);
//        }).collect(Collectors.toList());
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(items.toArray(new String[]{}));
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void cleanSet(String setName) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(setName);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void cleanHash(String hashName) {

        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(hashName);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void putHash(String hashName, String key, Object value) {
        Jedis jedis = jedisPool.getResource();
        try {
            if(value instanceof String){
                jedis.hset(hashName, key, (String) value);
                return;
            }
            JsonSerializer valueSerializer = new JsonSerializer(value.getClass());
            String valueByte = valueSerializer.serialize(value);
            jedis.hset(hashName, key, valueByte);
        } finally {
            // jedis.quit();
            jedis.close();
        }

    }

    @Override
    public void addSet(String setName, Object value) {
        Jedis jedis = jedisPool.getResource();
        try {

            if(value instanceof String){
                jedis.sadd(setName, (String) value);
                return;
            }
            JsonSerializer valueSerializer = new JsonSerializer(value.getClass());
            String valueByte = valueSerializer.serialize(value);

            jedis.sadd(setName, valueByte);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void addList(String listName, Object value) {
        Jedis jedis = jedisPool.getResource();
        try {

            if(value instanceof String){
                jedis.lpush(listName, (String) value);
                return;
            }
            JsonSerializer valueSerializer = new JsonSerializer(value.getClass());
            String valueByte = valueSerializer.serialize(value);

            jedis.lpush(listName, valueByte);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public <T> T getHash(String hashName, String key, Type clazz) {
        Jedis jedis = jedisPool.getResource();
        try {

            String json = jedis.hget(hashName, key);

            if(clazz == String.class){
                return (T) json;
            }
            JsonSerializer valueSerializer = new JsonSerializer(clazz);
            return (T) valueSerializer.deserialize(json);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public <T> Map<String, T> getHash(String hashName, Type clazz) {
        Jedis jedis = jedisPool.getResource();
        try {


            Map<String, String> cacheMap = jedis.hgetAll(hashName);

            if(clazz == String.class){
                return (Map<String, T>) cacheMap;
            }

            JsonSerializer valueSerializer = new JsonSerializer(clazz);
            Map<String, T> result = new HashMap<>();
            cacheMap.forEach((k, v) -> {
                result.put(k, (T) valueSerializer.deserialize(v));
            });
            return result;
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void removeSet(String setName, String value) {
        Jedis jedis = jedisPool.getResource();
        try {

            long result = jedis.srem(setName, value);
            if(result == 0){
                Set<String> member = jedis.smembers(setName);
                member.size();
            }
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public long sizeOfHash(String hashName) {
        Jedis jedis = jedisPool.getResource();
        try {

            Long size = jedis.hlen(hashName);
            return size == null ? 0 : size;
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public long sizeOfSet(String setName) {
        Jedis jedis = jedisPool.getResource();
        try {

            Long size = jedis.scard(setName);
            return size == null ? 0 : size;
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public <T> Set<T> getSet(String setName, Class<T> clazz) {
        Jedis jedis = jedisPool.getResource();
        try {

            Set<String> set = jedis.smembers(setName);
            if(set == null || set.isEmpty()){
                return new HashSet<>();
            }

            if(clazz == String.class){
                return (Set<T>) set;
            }

            Set<T> result = new HashSet<>();
            JsonSerializer valueSerializer = new JsonSerializer(clazz);
            for(String s : set){
                result.add((T) valueSerializer.deserialize(s));
            }

            return result;
        } finally {
            // jedis.quit();
            jedis.close();
        }

//        JsonSerializer<T> serializer = new JsonSerializer(clazz);
//        return set.stream().map(serializer::deserialize).collect(Collectors.toSet());
    }

    @Override
    public boolean containHash(String hashName) {
        Jedis jedis = jedisPool.getResource();
        try {

            return jedis.exists(hashName);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public <T> T get(String key, Class<T> clazz) {
        Jedis jedis = jedisPool.getResource();
        try {

            String result = jedis.get(key);
            if(clazz == String.class){
                return (T) result;
            }

            JsonSerializer valueSerializer = new JsonSerializer(clazz);
            return (T) valueSerializer.deserialize(result);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public <T> void put(String key, T t) {
        Jedis jedis = jedisPool.getResource();
        try {

            if(t instanceof String){
                jedis.set(key, (String) t);
                return;
            }
            JsonSerializer valueSerializer = new JsonSerializer(t.getClass());
            String json = valueSerializer.serialize(t);
            jedis.set(key, json);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void cleanValue(String key) {
        Jedis jedis = jedisPool.getResource();
        try {

            jedis.del(key);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public <T> List<T> getList(String key, Type clazz) {
        Jedis jedis = jedisPool.getResource();
        try {

            long length = jedis.llen(key);
            List<String> set = jedis.lrange(key, 0, length - 1);
            if(set == null || set.isEmpty()){
                return new ArrayList<>();
            }

            if(clazz == String.class){
                return (List<T>) set;
            }

            List<T> result = new ArrayList<>();
            JsonSerializer valueSerializer = new JsonSerializer(clazz);
            for(String s : set){
                result.add((T) valueSerializer.deserialize(s));
            }

            return result;
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }

    @Override
    public void cleanList(String key) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.del(key);
        } finally {
            // jedis.quit();
            jedis.close();
        }
    }
}
